/**
 * 修改动作
 */
function sModifyAction(type){
    var _type = type;

    /**
     * 变异元素的修改范围
     */
    var range = {
        start: 0,
        end: 0
    };

    /**
     * 修改元素集合
     */
    var elements = [];

    /**
     * 选择范围对象映射
     */
    var selection_ranges = {};

    /**
     * 动作发生时的偏移量
     */
    var _offset = null;

    /**
     * 动作发生时的选项
     */
    var _opt = null;

    /**
     * 反转前置函数
     */
    var _reverse = null;

    /**
     * 恢复前置函数
     */
    var _recover = null;

    /**
     * 留痕状态
     */
    var _leaveTrace = false;

    /**
     * 最后一个选择区间元素或非选择区间所在元素
     */
    var _lastInElement = null;

    var _actType = null;

    /**
     * 获取动作类型
     */
    this.getActType = function(){
        return _actType ? _actType : ssDict.sActionType.MODIFY;
    }

    this.setActType = function(actType){
        _actType = actType;
    }

    /**
     * 获取区域类型
     * @returns 
     */
    this.getType = function(){
        return _type;
    }

    /**
     * 设置留痕状态
     * @param {*} status true留痕 false不留痕
     */
    this.setLeaveTrace = function(status){
        _leaveTrace = status;
    }

    /**
     * 设置选择范围
     * @param {*} selectionRange 选择范围对象
     * @param {*} before 动作之前
     */
    this.setSelectionRange = function(selectionRange, before){
        selection_range = {
            startOffset: null,
            endOffset: null,
            __position: selectionRange.__position
        };

        selection_range.startOffset = this.deepCloneOffset(selectionRange.startOffset);
        selection_range.endOffset = this.deepCloneOffset(selectionRange.endOffset);

        selection_ranges[before ? "reverse" : "recover"] = selection_range;
    }

    /**
     * 设置动作发生时偏移量
     * @param {*} offset 
     * @param {*} opt 
     */
    this.setOffset = function(offset, opt) {
        _offset = offset;
        _opt = opt;
    }

    /**
     * 反转前置函数
     * @param {*} beforeReverse 
     */
    this.setBeforeReverse = function(beforeReverse){
        _reverse = beforeReverse;
    }

    /**
     * 恢复前置函数
     * @param {*} beforeRecover 
     */
    this.setBeforeRecover = function(beforeRecover){
        _recover = beforeRecover;
    }

    /**
     * 返回反转前置函数
     * @returns 
     */
    this.beforeReverse = function(){
        return _reverse;
    }

    /**
     * 返回恢复前置函数
     * @returns 
     */
    this.beforeRecover = function(){
        return _recover;
    }

    /**
     * 添加修改元素
     * @param {*} element 
     * @param {*} opt
     */
    this.add = function(element, offset, opt){
        var el = {
            element: element,
            offset: this.deepCloneOffset(offset),
            ...opt
        };

        elements.push(el);

        return this;
    }

    /**
     * 变异文本元素，一个action只能执行一次
     * @param {*} element 
     * @param {*} text 
     * @param {*} offset 
     * @param {*} opt
     */
    this.mutateText = function(element, text, offset, opt){
        if(!_leaveTrace){
            return mutateText.call(this, element, text, offset);
        }else{
            return mutateTextForLeaveTrace.call(this, element, text, offset, opt);
        }
    }

    /**
     * 变异文本元素，一个action只能执行一次
     * @param {*} element 文本元素
     * @param {*} text 新增文本内容
     * @param {*} offset 元素偏移量
     */
    var mutateText = function(element, text, offset){
        var rootOffset = this.deepCloneOffset(offset);
        var offset = this.extractDeepOffset(rootOffset);

        var innerText = "";
        var hasPlaceholder = element.placeholder != null && element.placeholder.length > 0;
        var hasInnerText = element.innerText != null && element.innerText.length > 0;

        //在文本元素指定placeholder时，存在排版文本__texts，但是innerText为空的情况
        if(hasInnerText || (!hasInnerText && !hasPlaceholder)){
            var pText = element.__texts[offset.pageIndex];
            var rText = pText[offset.rowIndex];
    
            rText = rText.substr(0, offset.contentIndex + 1) + 
                text + 
                rText.substr(offset.contentIndex + 1);
    
            for(var i in element.__texts){
                pText = element.__texts[i];
                for(var j in pText){
                    if(i < offset.pageIndex || (i == offset.pageIndex && j < offset.rowIndex)){
                        range.start += pText[j].length;
                    }
                    innerText += i == offset.pageIndex && j == offset.rowIndex ? rText : pText[j];
                }
            }
        }else{
            innerText = text;
        }

        range.start += (!element.innerText && offset.contentIndex > -1)
            ? offset.contentIndex : 
            offset.contentIndex + 1;
        range.end = range.start + text.length;

        rootOffset.range = range;

        var result = {
            element: element,
            oldContent: element.innerText,
            newContent: innerText,
            offset: rootOffset,
            mutate: true
        };

        element.innerText = innerText;

        elements.push(result);

        return this;
    }

    /**
     * 变异文本元素，一个action只能执行一次(留痕状态)
     * @param {*} element 
     * @param {*} text 
     * @param {*} offset 
     * @param {*} opt
     */
    var mutateTextForLeaveTrace = function(element, text, offset, opt){
        opt = opt ? opt : {};

        var next = this.extractDeepOffset(offset);
        if(next.start == null){
            this.mergeOffsetNext(offset, {
                start: next.contentIndex,
                end: next.contentIndex
            });
        }

        var splitText = this.splitText(element, [offset]);
        
        if(splitText.inText){
            splitText.rightText = splitText.inText;
        }

        splitText.inText = text;

        opt.leftTextEmptyCreate = element.delete;
        opt.mutateStyle = { doubleDash: "bottom" };
        var result = this.composeElements(splitText, element, offset, this.wrapElement, opt);

        if(result.leftElement){
            this.mergeOffsetNext(result.leftElement.offset, {
                range: {
                    start: result.leftElement.element.innerText.length,
                    end: result.leftElement.element.innerText.length
                }
            });
            elements.push(result.leftElement);
        }

        if(result.inElement){
            result.inElement.element.new = true;
            delete result.inElement.element.delete;

            this.mergeOffsetNext(result.inElement.offset, {
                range: {
                    start: result.inElement.element.innerText.length,
                    end: result.inElement.element.innerText.length
                }
            });

            elements.push(result.inElement);
            _lastInElement = result.inElement;
        }

        if(result.rightElement){
            this.mergeOffsetNext(result.rightElement.offset, {
                range: {
                    start: result.rightElement.element.innerText.length,
                    end: result.rightElement.element.innerText.length
                }
            });
            result.rightElement.notLocate = true;
            elements.push(result.rightElement);
        }

        return this;
            
        // return mutateText.call(this, element, text, offset);
    }

    /**
     * 变异文本样式
     * @param {*} element 
     * @param {*} offset
     * @param {*} style 
     */
    this.mutateTextStyle = function(element, offset, style){
        let oldStyle = {...element.style};
        let newStyle = {...oldStyle, ...style};

        element.style = newStyle;
        offset.range = {
            start: -1,
            end: -1
        };

        var result = {
            element: element,
            oldStyle: oldStyle,
            newStyle: newStyle,
            offset: offset,
            mutate: true
        };

        elements.push(result);
    }

    /**
     * 判断变异样式是否和指定元素样式存在差异
     * @param {*} element 
     * @param {*} mutateStyle 
     * @returns 
     */
    this.canMutateStyle = function(element, mutateStyle){
        for(var i in mutateStyle){
            if(element.style[i] != mutateStyle[i]){
                return true;
            }
        }
        return false;
    }

    /**
     * 根据选择偏移量分割文本元素
     * @param {*} element 元素
     * @param {*} offsets 元素偏移量
     * @param {*} mutateStyle 变异样式
     * @param {*} opt 可选参数 
     */
    this.divideTextForSelection = function(element, offsets, mutateStyle, opt){
        opt = opt ? opt : {};

        opt.mutateStyle = mutateStyle;

        var splitText = this.splitText(element, offsets);
        var result = this.composeElements(splitText, element, offsets[0], this.wrapElement, opt);

        if(result.leftElement){
            elements.push(result.leftElement);
        }

        if(result.inElement){
            var next = this.extractDeepOffset(result.inElement.offset);
            this.mergeOffsetNext(result.inElement.offset, {
                range: {
                    start: next.start,
                    end: next.end
                }
            });

            if(opt.annotation){
                result.inElement.element.annotation = {
                    id: opt.annotationId,
                    type: opt.annotationType
                };
                result.inElement.element.annotationChildren = [...opt.annotationElements]
            }
            
            elements.push(result.inElement);
            
            _lastInElement = result.inElement;
        }

        if(result.rightElement){
            elements.push(result.rightElement);

            this.changeAnnotation(result.leftElement 
                ? result.leftElement.element : result.inElement.element, result.rightElement.element);
        }

        return this;
    }

    /**
     * 变异段落元素
     * @param {*} element 
     * @param {*} offset
     * @param {*} mutateStyle 
     */
    this.mutateParagraph = function(element, offset, mutateStyle){
        var style = {...element.style, ...mutateStyle};
        var el = {
            element: element,
            oldStyle: element.style,
            newStyle: style,
            offset: this.deepCloneOffset(offset),
            mutate: true
        };
        
        element.style = style;
        elements.push(el);
    }

    /**
     * 变异包装元素
     * @param {*} element 
     * @param {*} offset 
     * @param {*} mutateStyle 
     * @param {*} attributes 
     */
    this.mutateWrapElement = function(element, offset, mutateStyle, attributes){
        if(element._sType == "sLayer"){
            this.mutateLayer(element, offset, mutateStyle);
        }else if(element._sType == "sInputBegin" || element._sType == "sInputEnd"){
            this.mutateInputArea(element, offset, mutateStyle, attributes);
        } 
    }

    /**
     * 变异层元素
     * @param {*} element 
     * @param {*} offset
     * @param {*} mutateStyle 
     */
    this.mutateLayer = function(element, offset, mutateStyle){
        var style = {...element.style, ...mutateStyle};
        var el = {
            element: element,
            oldStyle: element.style,
            newStyle: style,
            offset: this.deepCloneOffset(offset),
            mutate: true
        };
        
        element.style = style;
        elements.push(el);
    }

    /**
     * 变异输入域
     * @param {*} element 
     * @param {*} offset 
     * @param {*} mutateStyle
     * @param {*} attributes 
     */
    this.mutateInputArea = function(element, offset, mutateStyle, attributes){
        var el = {
            element: element,
            offset: this.deepCloneOffset(offset),
            mutate: true
        };

        if(mutateStyle){
            var style = {...element.style, ...mutateStyle};
            el.oldStyle = element.style;
            el.newStyle = style;
            element.style = style;
        }
        
        elements.push(el);
    }

    /**
     * 变异单元格
     * @param {*} element 
     * @param {*} offset 
     * @param {*} mutateStyle 
     * @param {*} props
     */
    this.mutateTableCell = function(element, offset, mutateStyle, props){
        var style = {...element.style, ...mutateStyle};
        var el = {
            element: element,
            oldStyle: element.style,
            newStyle: style,
            offset: this.deepCloneOffset(offset),
            mutate: true
        };

        if(props){
            if(props.rowspan){
                el.oldRowspan = element.rowspan;
                element.rowspan = props.rowspan;
            }
    
            if(props.colspan){
                el.oldColspan = element.colspan;
                element.colspan = props.colspan;
            }
        }
        
        element.style = style;
        elements.push(el);
    }

    /**
     * 变异表格行元素
     * @param {*} element 列元素
     * @param {*} offset 偏移量
     * @param {*} mutateStyle 变异样式
     * @param {*} table 所属表格元素
     */
    this.mutateTableRow = function(element, offset, mutateStyle, table){
        var style = {...element.style, ...mutateStyle};
        var el = {
            element: element,
            oldStyle: element.style ? element.style : {},
            newStyle: style,
            offset: this.deepCloneOffset(offset),
            table: table,
            mutate: true
        };

        element.style = style;
        elements.push(el);
    }

    /**
     * 变异表格列元素
     * @param {*} element 列元素
     * @param {*} offset 偏移量
     * @param {*} mutateStyle 变异样式
     * @param {*} table 所属表格元素
     */
    this.mutateTableCol = function(element, offset, mutateStyle, table){
        var style = {...element.style, ...mutateStyle};
        var el = {
            element: element,
            oldStyle: element.style,
            newStyle: style,
            offset: this.deepCloneOffset(offset),
            table: table,
            mutate: true
        };

        element.style = style;
        elements.push(el);
    }

    /**
     * 获取所有元素
     * @returns 
     */
    this.getElements = function(){
        return elements;
    }

    /**
     * 获取新增内容在元素中的范围
     * @returns 
     */
    this.getRange = function(){
        return range;
    }

    /**
     * 获取最后一个选择区间元素或非选择区间所在元素
     * @returns 
     */
    this.getLastInElement = function(){
        if(!_lastInElement) return null;
        
        return {
            position: _type,
            ref: _lastInElement.element,
            offset: _lastInElement.offset
        };
    }

    /**
     * 返回当前动作的反向动作
     */
    this.reverse = function(){
        var result = {
            type: _type,
            elements: [],
            offset: _offset,
            selectionRange: selection_ranges.reverse
        };

        var el = null;
        var elc = null;

        for(var i in elements){
            el = elements[i];

            if(el.mutateNew){
                elc = {...el};
                elc.delete = true;

                if(elc.element.__boundRect){
                    elc.delRange = this.getElementPageRange(elc.element);
                    elc.offset = {
                        pageIndex: elc.delRange.startPageIndex,
                        rowIndex: elc.delRange.startRowIndex
                    };
                }else{
                    elc.offset = this.deepCloneOffset(elc.offset);
                }

                delete elc.mutateNew;

                result.delete = true;
            }else if(el.mutate){
                elc = {...el};

                if(elc.oldContent != null){
                    elc.element.innerText = elc.oldContent;
                }

                if(elc.oldStyle != null){
                    elc.element.style = elc.oldStyle;
                }

                if(!elc.offset.pageIndex && elc.element.__boundRect){
                    var elRange = this.getElementPageRange(elc.element);
                    elc.offset = {
                        pageIndex: elRange.startPageIndex,
                        rowIndex: elRange.startRowIndex
                    };

                    if(el.element.innerText){
                        elc.offset.range = {
                            start: elc.element.innerText.length,
                            end: elc.element.innerText.length
                        }
                    }else{
                        elc.offset.range = {
                            start: 1,
                            end: 1
                        }
                    }
                }else{
                    elc.offset = this.deepCloneOffset(el.offset);
                    if(el.offset.range){
                        elc.offset.range.start = el.offset.range.start;
                        elc.offset.range.end = el.offset.range.start;
                    }
                }

                if(!result.offset){
                    result.offset = elc.offset;
                }

                this.clearMiddleProperties(elc);
            }

            result.elements.push(elc);
        }

        return result;
    }

    /**
     * 将反向动作恢复成正向动作
     */
    this.recover = function(){
        var result = {
            type: _type,
            elements: [],
            offset: _offset,
            opt: _opt,
            selectionRange: selection_ranges.recover
        };

        var el = null;
        var elc = null;

        for(var i in elements){
            el = elements[i];

            if(el.mutateNew){
                elc = {...el};
            }else if(el.mutate){
                elc = {...el};

                if(elc.newContent != null){
                    elc.element.innerText = elc.newContent;
                }

                if(elc.newStyle != null){
                    elc.element.style = elc.newStyle;
                }

                elc.offset = this.deepCloneOffset(el.offset);

                if(elc.element.__boundRect){
                    var elRange = this.getElementPageRange(elc.element);
                    if(!this.isOffsetInRange(elc.offset, elRange)){
                        this.mergeOffsetNext(elc.offset, {
                            pageIndex: elRange.startPageIndex,
                            rowIndex: elRange.startRowIndex     
                        });     
                    }
                }
    
                if(!result.offset){
                    result.offset = elc.offset;
                }
            }

            result.elements.push(elc);
        }

        return result;
    }
}